package com.airS.task.fileMgr.security.shiro.filter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.airS.task.fileMgr.common.anno.Invoke;
import com.airS.task.fileMgr.common.em.LogType;
import com.airS.task.fileMgr.common.response.BaseResponse;
import com.airS.task.fileMgr.common.response.ResponseCode;
import com.airS.task.fileMgr.security.shiro.realm.SystemAuthorizingRealm;
import com.airS.task.fileMgr.security.shiro.session.RedisSessionDAO;
import com.airS.task.fileMgr.security.shiro.token.UsernamePasswordToken;
import com.airS.task.fileMgr.utils.servlet.ServletUtils;
import com.airS.task.fileMgr.utils.url.UrlUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.session.Session;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;


/**
 * 表单验证过滤类
 * Created by alan on 2017/3/14.
 */
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter implements InitializingBean {

    public static final String DEFAULT_USERNAME_PARAM = "account";
    public static final String DEFAULT_PASSWORD_PARAM = "password";
    public static final String DEFAULT_REMEMBER_ME_PARAM = "isRemember";
    public static final String DEFAULT_MESSAGE_PARAM = "loginFailureMessage";

    private String messageParam = DEFAULT_MESSAGE_PARAM;

    /**
     * 创建自定义token，扩展
     * @param request
     * @param response
     * @return
     */
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        String username = getUsername(request);
        String password = getPassword(request);
        if (password == null) {
            password = "";
        }
        boolean rememberMe = isRememberMe(request);
        String host = UrlUtils.getRemoteAddr((HttpServletRequest) request);
        return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host);
    }

    /**
     * 登录成功之后跳转URL
     */
    public String getSuccessUrl() {
        return super.getSuccessUrl();
    }

    @Override
    protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        // 检查会话管理器是否连接异常
        if(httpServletRequest.getAttribute(RedisSessionDAO.SESSION_CONNECT_TIME_OUT) != null){
            if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {
                WebUtils.issueRedirect(request, response, getLoginUrl(), null, true);
            } else {
                BaseResponse baseResponse = new BaseResponse();
                baseResponse.setCode(ResponseCode.SESSION_CONNECT_TIME_OUT);
                ServletUtils.writeJson(baseResponse, response);
            }
            return;
        }

        if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-With"))) {
            WebUtils.issueRedirect(request, response, getSuccessUrl(), null, true);
        } else {
            BaseResponse baseResponse = new BaseResponse();
            baseResponse.setCode(ResponseCode.SUCCESS);
            ServletUtils.writeJson(baseResponse, response);
        }
    }

    /**
     * 登录失败调用事件
     * @param token
     * @param e
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request,
                                     ServletResponse response) {
        String className = e.getClass().getName(), message = "";
        if (IncorrectCredentialsException.class.getName().equals(className)
                || UnknownAccountException.class.getName().equals(className)) {
            message = "用户或密码错误，请重试";
        } else if (e.getMessage() != null && StringUtils.startsWith(e.getMessage(), "msg:")) {
            message = StringUtils.replace(e.getMessage(), "msg:", "");
        } else {
            message = "系统出现点问题，请稍后再试";
            e.printStackTrace(); // 输出到控制台
        }
        request.setAttribute(getFailureKeyAttribute(), className);
        request.setAttribute(getMessageParam(), message);
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setUsernameParam(DEFAULT_USERNAME_PARAM);
        setPasswordParam(DEFAULT_PASSWORD_PARAM);
        setRememberMeParam(DEFAULT_REMEMBER_ME_PARAM);
    }

    public String getMessageParam() {
        return messageParam;
    }

    public void setMessageParam(String messageParam) {
        this.messageParam = messageParam;
    }
}